using System;
using System.Resources;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.ComponentModel;
using System.Text;
using System.IO;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using System.Xml;


namespace Dynamic_BAM_Pipeline_Components
{

    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    [ComponentCategory(CategoryTypes.CATID_Validate)]
    [System.Runtime.InteropServices.Guid("9d0e4103-4cce-4536-83fa-4a5040674ad6")]
    public class BAM_Tracking_Receive_Component :
        IBaseComponent,
        Microsoft.BizTalk.Component.Interop.IComponent,
        Microsoft.BizTalk.Component.Interop.IPersistPropertyBag,
        IComponentUI
    {
        static ResourceManager resManager = new ResourceManager("Sample_Dynamic_BAM_Pipeline_Components.BAM_Tracking_Component", Assembly.GetExecutingAssembly());


        // Component information

        public string Name { get { return "BAM Tracking Component"; } }
        public string Version { get { return "1.0"; } }
        public string Description { get { return "Sample Component for using the BAM API within a Pipeline Component"; } }
        public IntPtr Icon
        {
            get
            {
                return new System.IntPtr();
            }
        }
        public System.Collections.IEnumerator Validate(object projectSystem)
        {
            return null;
        }
        private string _activityNames;
        [
        DisplayName("Activities to Track"),
        Description(@"Please enter activity names separated by a semicolon: GeneralMessageInfo;Invoice")
        ]
        public string ActivityNames
        {
            get { try { return _activityNames; } catch { } return null; }
            set { try {_activityNames = value;} catch { } }
        }

        private string _storeMessageBody;
        [
        DisplayName("Store Message Body (Yes, No)"),
        Description(@"Enter Yes or No to persist the message body.  This is limited to message bodies under 1MB")
        ]
        public string StoreMessageBody
        {
            get { try { return _storeMessageBody; } catch { } return null; }
            set { try { _storeMessageBody = value; } catch { } }
        }
        private string _activityForMessageBody;
        [
        DisplayName("Activity to relate Message Body with"),
        Description(@"This specifies the activity for which the message body will be related: GeneralMessageInfo")
        ]
        public string ActivityForMessageBody
        {
            get { try { return _activityForMessageBody; } catch { } return null; }
            set { try { _activityForMessageBody = value; } catch { } }
        }
        private string _directToBamPrimary;
        [
        DisplayName("Store BAM Data Directly to BAMPrimary Import (Yes, No)"),
        Description(@"Enter Yes or No to send the data directly to the BAM Primary Import (Direct) or No to use the TDDS Tracking service (Buffered).")
        ]
        public string DirectBAMStorage
        {
            get { try { return _directToBamPrimary; } catch { } return null; }
            set { try { _directToBamPrimary = value; } catch { } }
        }
        private string _bamPrimaryConnectionString;
        [
        DisplayName("BAM Database Connection String for Direct Writes"),
        Description(@"Enter something like the following: Integrated Security=SSPI;Data Source=localhost;Initial Catalog=BAMPrimaryImport")
        ]
        public string DirectBAMStorageConnection
        {
            get { try { return _bamPrimaryConnectionString; } catch { } return null; }
            set { try { _bamPrimaryConnectionString = value; } catch { } }
        }

        public void InitNew()
        {
        }

        public void GetClassID(out Guid classID)
        {
            classID = new Guid("48BEC85A-20EE-40ad-BFD0-319B59A0DDBC");
        }

        public void Load(IPropertyBag propertyBag, int errorLog)
        {
            string val = (string)ReadPropertyBag(propertyBag, "ActivityNames");
            if (val != null) ActivityNames = val;
            val = (string)ReadPropertyBag(propertyBag, "DirectBAMStorageConnection");
            if (val != null) DirectBAMStorageConnection = val;
            val = (string)ReadPropertyBag(propertyBag, "StoreMessageBody");
            if (val != null) StoreMessageBody = val;
            val = (string)ReadPropertyBag(propertyBag, "DirectBAMStorage");
            if (val != null) DirectBAMStorage = val;
            val = (string)ReadPropertyBag(propertyBag, "ActivityForMessageBody");
            if (val != null) ActivityForMessageBody = val;

        }
        public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
            object val = (object)ActivityNames;
            WritePropertyBag(propertyBag, "ActivityNames", val);
            val = (object)StoreMessageBody;
            WritePropertyBag(propertyBag, "StoreMessageBody", val);
            val = (object)DirectBAMStorage;
            WritePropertyBag(propertyBag, "DirectBAMStorage", val);
            val = (object)DirectBAMStorageConnection;
            WritePropertyBag(propertyBag, "DirectBAMStorageConnection", val);
            val = (object)ActivityForMessageBody;
            WritePropertyBag(propertyBag, "ActivityForMessageBody", val);
        }



        ArrayList _activitiesRequested = null;
        string _msgType = "";
        StringBuilder _perfList;
        public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            
            _activitiesRequested = new ArrayList();
            if (ActivityNames != null)
            {
                if (ActivityNames.Contains(";"))
                {
                    foreach (string activityName in ActivityNames.Split(';'))
                    {
                        if (activityName != "")
                        {
                            _activitiesRequested.Add(activityName.Trim());
                        }
                    }
                }
                else
                {
                    _activitiesRequested.Add(ActivityNames.ToString().Trim());
                }
            }
            else  //There are no activity names defined
            {
                return pInMsg;
            }

            //If no activities are requested return immediately.
            if (_activitiesRequested.Count == 0)
            {
                return pInMsg;
            }
            
            //Seekable stream will allow us to rewind the stream when needed.
            Microsoft.BizTalk.Streaming.ReadOnlySeekableStream _seekableStream = null;
            
            bool _directWrite = false;
            if(_directToBamPrimary.ToLower() == "yes")
            {
                _directWrite = true;
            }
            bool _saveMsgBody = false;
            if (_storeMessageBody.ToLower() == "yes")
            {
                _saveMsgBody = true;
            }
            try
            {
                //Get the context properties
                string systemPropertiesNamespace = @"http://schemas.microsoft.com/BizTalk/2003/system-properties";
                IBaseMessageContext context = pInMsg.Context;
                _msgType = context.Read("MessageType", systemPropertiesNamespace) as string;
                XmlDocument _bamDocument = null;
                Generated_BAM_Pipeline_Queries.IBamMessage _bamMessage;
                foreach (string Activity in _activitiesRequested)
                {
                    //Check to see if this message type has a #.  In some EDI Messages the msg type is proceeded by the namespace
                    if (_msgType != null)
                    {
                        if (!_msgType.Contains("#"))
                        {
                            _msgType = "#" + _msgType;
                        }
                    }
                    else //MSG Type could  be null if this is a pass through scenario
                    {
                        _msgType = "No Message Type Retreived from Context";
                    }
                    //Does this messageType have this activity defined?
                    //SAP Specific challenge here.  All SAP messages are going to show up as Receive.  This means we need to include namespace as well in the generateMessage
                    if (Generated_BAM_Pipeline_Queries.BAMActivityDispatcher.ActivityExistsForMessage(_msgType, Activity))
                    {
                        _bamMessage = Generated_BAM_Pipeline_Queries.BAMActivityDispatcher.CreateBAMMessage(_msgType, Activity);
                        if (_bamMessage.HasDataProperties)
                        {
                            //Create a new instance of the seekable stream if it isnt already there.  This is needed when we look into the message to retreive data properties as in a map.
                            if (_seekableStream == null && _bamMessage.HasDataProperties)
                            {
                                _seekableStream = new Microsoft.BizTalk.Streaming.ReadOnlySeekableStream(pInMsg.BodyPart.GetOriginalDataStream());
                            }
                            _bamMessage.TransformAndSave(_seekableStream, pContext, context, _directWrite, DirectBAMStorageConnection, pInMsg.MessageID.ToString(),_saveMsgBody,null);
                            //Upload any context as needed
                            if (_bamMessage.HasUploadProperties)
                            {
                                _bamMessage.UploadContextPropertiesIntoMessage(pContext, context, pInMsg.MessageID.ToString());
                            }
                            //Save off the BAMDocument so that the next activity wont have to rerun the map
                            _bamDocument = _bamMessage.BAMActivitiesDocument;
                            //Reset the position for the next activity
                            _seekableStream.Position = 0;
                        }
                        else //This is a context only request just save off the context and methods
                        {
                            _bamMessage.SaveContextOnly(pContext, context, _directWrite, DirectBAMStorageConnection, pInMsg.MessageID.ToString(),_saveMsgBody,null);
                        }
                    }
                    else //Check to see if this activity exists for all message types.
                    {
                        if (Generated_BAM_Pipeline_Queries.BAMActivityDispatcher.ActivityExistsForMessage("AllMessageTypes", Activity))
                        {
                            _bamMessage = Generated_BAM_Pipeline_Queries.BAMActivityDispatcher.CreateBAMMessage("AllMessageTypes", Activity);
                            _bamMessage.SaveContextOnly(pContext, context, _directWrite, DirectBAMStorageConnection, pInMsg.MessageID.ToString(),_saveMsgBody,null);
                            //Upload any context as needed
                            if (_bamMessage.HasUploadProperties)
                            {
                                _bamMessage.UploadContextPropertiesIntoMessage(pContext, context, pInMsg.MessageID.ToString());
                            }
                        }
                    }
                }

                if (_seekableStream != null)
                {
                    if (_seekableStream.Position != 0)
                    {
                        _seekableStream.Position = 0;
                    }
                    pInMsg.BodyPart.Data = _seekableStream;
                }

            }
            catch(System.Exception emsg)
            {
                System.Diagnostics.Debug.WriteLine(emsg.Message);
            }
            return pInMsg;
        }
        #region PropertyBag Methods
        /// <summary>
        /// Reads property value from property bag.
        /// </summary>
        /// <param name="pb">Property bag.</param>
        /// <param name="propName">Name of property.</param>
        /// <returns>Value of the property.</returns>
        private static object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
        {
            object val = null;
            try
            {
                pb.Read(propName, out val, 0);
            }

            catch (ArgumentException)
            {
                return val;
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
            return val;
        }

        /// <summary>
        /// Writes property values into a property bag.
        /// </summary>
        /// <param name="pb">Property bag.</param>
        /// <param name="propName">Name of property.</param>
        /// <param name="val">Value of property.</param>
        private static void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
        {
            try
            {
                pb.Write(propName, ref val);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }

        #endregion
    }
}
     

